package com.bruce.shop.commons.web;

import com.bruce.shop.commons.constans.ShopConstants;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @author BruceXia
 * @version 1.0.0
 * @description:协调和组织不同的servlet完成请求处理并返回响应的工作
 * @date 2022/9/1719:21
 */
public class DispatcherServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String requestURI = req.getRequestURI();

        String actionName = getActionName(requestURI);

        Method actionMethod = findActionMethod(actionName);

        if (actionMethod != null) {
            // 调用方法
            String result = invoteActionMethod(actionMethod, req, resp);

            // 响应浏览器
            if (result != null && !"".equals(requestURI)) {
                responceClient(result, req, resp);
            }
        } else {
            System.out.println("没有找到action:" + actionName);
        }
    }

    /**
     * 响应浏览器
     * @param result
     * @param req
     * @param resp
     * @throws IOException
     * @throws ServletException
     */
    private void responceClient(String result, HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
        // 1.拆分
        String[] split = result.split(":");
        String type = split[0]; // 跳转的方式
        String page = split[1]; // 跳转的页面

        // 2.判断
        if (ShopConstants.FORWARD.equals(type)) {
            req.getRequestDispatcher(req.getContextPath() + "/" + page).forward(req, resp);
        } else if (ShopConstants.REDIRECT.equals(type)) {
            resp.sendRedirect(req.getContextPath() + "/" + page);
        } else if (ShopConstants.SCRIPT.equals(type)) { // js代码
            resp.setContentType("text/html;charset=utf8");
            resp.getWriter().write("<script>alert('" + page + "');window.history.back();</script>");
        } else if (ShopConstants.JSON.equals(type)) { // 响应JSON内容
            int index = result.indexOf(":");
            String json = result.substring(index + 1);
            resp.getWriter().write(json);
        }
    }


    /**
     * 通过invoke调用找到的action方法
     * 反射包下的Method类调用invoke方法，调用我们所提供的方法以及调用方法的参数来完成动态调用。
     * 也就是根据你给的对象/实例，方法名，以及参数来调用。找了个“替身”来帮你调用方法。
     * @param actionMethod
     * @param request
     * @param response
     * @return
     */
    private String invoteActionMethod(Method actionMethod, HttpServletRequest request, HttpServletResponse response) {
        try {
            // 调用方法。req，resp是调用方法是传递的两个参数
            return (String) actionMethod.invoke(this, request, response);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 根据上一个方法获得的action name在Controller中找到对应的方法
     * @param actionName
     * @return
     */
    private Method findActionMethod(String actionName) {
        // 通过反射获取当前Controller中的所有方法！！！
        Method[] methods = this.getClass().getDeclaredMethods();

        //遍历获取的所有方法去一个个和这个得到的方法进行比较
        for (int i = 0; i < methods.length; i++) {
            Method method = methods[i];
            // 对比方法名称和actionName是否一致
            if (method.getName().equals(actionName)) {
                // 如果一致说明找到调用的方法
                return method;
            }
        }
        //如果没找到返回null
        return null;
    }

    /**
     * 获得用户调用的action的方法
     * @param requestURI
     * @return
     */
    private String getActionName(String requestURI) {
        //找到最后一个/后面的就是用户请求的action的name
        String actionName = requestURI.substring(requestURI.lastIndexOf("/") + 1);
        System.out.println("actionName:" + actionName);
        return actionName;
    }
}
